package fr.paris.lutece.plugins.${plugin.name}.business.dao;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import fr.paris.lutece.plugins.${plugin.name}.business.bean.${bean.name?cap_first};
import fr.paris.lutece.plugins.${plugin.name}.business.bean.${bean.name?cap_first}Filter;
import fr.paris.lutece.plugins.${plugin.name}.business.bean.${bean.name?cap_first}_;
import fr.paris.lutece.plugins.${plugin.name}.commons.ResultList;

/**
 * The ${bean.name?cap_first} DAO class
 * @author ${bean.author}
 */
public class ${bean.name?cap_first}DAO extends Abstract${plugin.name?cap_first}DAO<Integer, ${bean.name?cap_first}> implements I${bean.name?cap_first}DAO{

	/**
     * Build the criteria query used when offers are searched by filter.
     * 
     * @param filter the filter
     * @param root the offer root
     * @param query the criteria query
     * @param builder the criteria builder
     */
    protected void buildCriteriaQuery( ${bean.name?cap_first}Filter filter, Root<${bean.name?cap_first}> root, CriteriaQuery<${bean.name?cap_first}> query,
    	CriteriaBuilder builder )
	{
    	// predicates list
    	List<Predicate> listPredicates = new ArrayList<Predicate>(  );
    	//Join<${bean.name?cap_first}, Type${bean.name?cap_first}> type${bean.name?cap_first} = root.join( ${bean.name?cap_first}_.type${bean.name?cap_first}, JoinType.INNER );
    	
    	<#list bean.attributs?keys as key>
		<#if bean.attributs[key].filter>
			if ( ( filter.get${key?cap_first}() != null) )
	    	{
	    		listPredicates.add( builder.equal(root.get(${bean.name?cap_first}_._${key}) ,filter.get${key?cap_first}(  ) ) );
	    	}
		</#if>
		</#list>
    	//if ( !StringUtils.isBlank(filter.getIdType${bean.name?cap_first}()) )
    	//{
    	//	listPredicates.add( builder.equal( type${bean.name?cap_first}.get( Type${bean.name?cap_first}_.id ), filter.getIdType${bean.name?cap_first}(  ) ) );
    	//}
    	
    	if ( !listPredicates.isEmpty(  ) )
    	{
    		// add existing predicates to Where clause
    		query.where( listPredicates.toArray( new Predicate[listPredicates.size( )] ) );
    	}
	}
    
    /**
	 * Generate count query from criteria query and return a paged query.
	 * 
	 * @param <T> the generic type of criteria query
	 * @param criteriaQuery  criteria query
	 * @param paginationProperties  pagination data
	 * @return query paged
	 */
	protected <T> PagedQuery createPagedQuery(CriteriaQuery<T> criteriaQuery,
			PaginationProperties paginationProperties) {

		// Generate count query
		EntityManager em = getEM();
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
		countQuery.select(cb.count(countQuery.from(criteriaQuery.getResultType())));
		// Rebuild the roots if
		// if ( cq.getRoots( ).size( ) > 1 )
		// {
		countQuery.getRoots().clear();
		for (Root<?> root : criteriaQuery.getRoots()) {
			countQuery.getRoots().add(root);
		}
		// }
		if (criteriaQuery.getRestriction() != null) {
			countQuery.where(criteriaQuery.getRestriction()).distinct(true);
		}

		// Create the paged query
		PagedQuery pq = new PagedQuery(em.createQuery(criteriaQuery),
				em.createQuery(countQuery), paginationProperties);

		return pq;
	}

	/**
	 * 
	 * @param filter the filter
	 * @param paginationProperties the pagination property
	 * @return the result list of ${bean.name?cap_first} entity
	 */
	@SuppressWarnings("unchecked")
	public ResultList<${bean.name?cap_first}> find(${bean.name?cap_first}Filter filter, PaginationProperties paginationProperties){
		EntityManager em = getEM(  );
		CriteriaBuilder cb = em.getCriteriaBuilder(  );
		CriteriaQuery<${bean.name?cap_first}> cq = cb.createQuery( ${bean.name?cap_first}.class );

		Root<${bean.name?cap_first}> root = cq.from( ${bean.name?cap_first}.class );
		buildCriteriaQuery( filter, root, cq, cb );
		buildSortQuery( filter, root, cq, cb );
		cq.distinct( true );

		return createPagedQuery( cq, paginationProperties ).getResultList( );
	}
}